package com.xz.config;

import com.xz.MyPasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;


import javax.sql.DataSource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import java.io.IOException;

/**
 * @author XZ
 * @create 2021-12-24 21:45
 */
//注意这个类一定要放在自动扫描的包下，不然所有的配置都不会生效
//@Configuration//将当前类标记为配置类
@EnableWebSecurity//启用web环境下权限控制的功能
@Import(org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.class)
public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private MyPasswordEncoder myPasswordEncoder;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //super.configure(auth);
//        auth.inMemoryAuthentication()
//                .withUser("admin")
//                .password("123123")
//                .roles("ADMIN","学徒")
//                .authorities("外门弟子")
//                .and()
//                .withUser("Zelda")
//                .password("Zelda")
//                .authorities("SAVE", "EDIT")
//                .roles("大师")
//        ;
        auth.userDetailsService(myUserDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);

        //super.configure(http);注释掉将取消父类方法中的默认规则
        //对请求进行授权
        http.authorizeRequests()
                //使用 ANT 风格设置要授权的 URL
                .antMatchers("/layui/**", "/index.jsp")
                //允许上面使用 ANT 风格设置的全部请求
                .permitAll()
                .antMatchers("/level1/**")
                .hasRole("大师")
                .antMatchers("/level2/**")
                .hasAuthority("外门弟子")
                .and()
                .authorizeRequests()
                //其他未设置的全部请求
                .anyRequest()
                //需要认证
                .authenticated()
                .and()
                //设置未授权请求跳转到登录页面
                .formLogin()
                //指定登录页
                .loginPage("/index.jsp")
                .permitAll()
                // loginProcessingUrl()方法指定了登录地址，就会覆盖loginPage()方法中设置的默认值/index.jsp POST
                .loginProcessingUrl("/do/login.html")
                // 定制登录账号的请求参数名
                .usernameParameter("loginAcct")
                // 定制登录密码的请求参数名
                .passwordParameter("userPswd")
                .defaultSuccessUrl("/main.html")
                .and()
                //禁用csrf
//                .csrf()
//                .disable()
                //开启退出功能
                .logout()
                //指定退出请求的URL地址
                .logoutUrl("/do/logout.html")
                //退出成功后前往的地址
                .logoutSuccessUrl("/index.jsp")
                .and()
                .exceptionHandling()
//                .accessDeniedPage("/to/no/auth/page.html")
                .accessDeniedHandler(new AccessDeniedHandler() {
                    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
                        httpServletRequest.setAttribute("message", e.getMessage());
                        httpServletRequest.getRequestDispatcher("/WEB-INF/views/no_auth.jsp").forward(httpServletRequest, httpServletResponse);
                    }
                })
                .and()
                //开启remember-me功能
                .rememberMe()
                //定制remember-me名称
                //.rememberMeParameter("rememberMeParam")
                .tokenRepository(jdbcTokenRepository)
        ;
    }

}